﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DcsGauges.Gui.Gauges.Interfaces;
using DcsGauges.Shared.Exceptions;
using DcsGauges.Shared.DataStructures;

namespace DcsGauges.Gui.Gauges.ValueConverters
{
    class InterpolatingConverter : IGaugeValueConverter<float>
    {
        private IList<InOutMapping> interPoints                = null;

        public InterpolatingConverter(IList<InOutMapping> interpolationPoints)
        {
            if (interpolationPoints.Count < 2 || !IsSorted(interpolationPoints))
            {
                throw new DcsArgumentException(DcsA10PanelResources.ExcInteropolationConverterAtLeastTwo);
            }

            this.interPoints            = interpolationPoints;
        }

        public float Convert(float sourceValue)
        {
            if(sourceValue < this.interPoints.First().InValue)  return this.interPoints.First().OutValue;
            if(sourceValue > this.interPoints.Last().InValue)   return this.interPoints.Last().OutValue;

            int segmentStart                = this.findSegmentStart(sourceValue);
            var segmentStartMapping         = this.interPoints[segmentStart];
            var segmentEndMapping           = this.interPoints[segmentStart + 1];

            var conv                        = new LinearConverter(segmentStartMapping, segmentEndMapping, 0.0f);
            float result                   = conv.Convert(sourceValue);
            return result;
        }

        public float ConvertBack(float convValue)
        {
            throw new DcsNotSupportedException();
        }

        private bool IsSorted(IList<InOutMapping> points)
        {
            float curMax = points[0].InValue;
            for (int i = 1; i < points.Count; i++)
            {
                if(points[i].InValue< curMax)
                { 
                    return false;
                }
                else
                {
                    curMax = points[i].InValue;
                }
            }

            return true;
        }

        private int findSegmentStart(float sourceValue)
        {
            for (int i = 0; i < this.interPoints.Count - 1; i++)
            {
                if(sourceValue > this.interPoints[i].InValue && sourceValue < this.interPoints[i + 1].InValue)
                    return i;
            }

            return 0;
        }

        public float MinIn
        {
            get { return this.interPoints[0].InValue; }
        }

        public float MaxIn
        {
            get { return this.interPoints[interPoints.Count - 1].InValue; }
        }
    }
}
